<?php

namespace services\api;

use Yii;
use yii\base\Exception;
use yii\db\ActiveRecord;
use yii\web\UnprocessableEntityHttpException;
use common\helpers\ImageHelper;
use common\helpers\ArrayHelper;
use common\models\member\Member;
use common\models\api\AccessToken;
use common\components\Service;

/**
 * Class AccessTokenService
 * @package services\api
 */
class AccessTokenService extends Service
{
    /**
     * 是否加入缓存
     *
     * @var bool
     */
    public $cache = false;

    /**
     * 缓存过期时间
     *
     * @var int
     */
    public $timeout = 86400;

    /**
     * 获取token
     *
     * @param Member $member
     * @param int $cycle_index 重新获取次数
     * @return array
     * @throws Exception
     */
    public function getAccessToken(Member $member, $cycle_index = 1)
    {
        // 1.生成Token
        $model = new AccessToken();
//        $model = $this->findModel($member->id);
        $model->member_id = $member->id;

        // 删除缓存
//        !empty($model->access_token) && Yii::$app->redis->del($this->getCacheKey($model->access_token));
        $model->refresh_token = Yii::$app->security->generateRandomString() . '_' . time();
        $model->access_token = Yii::$app->security->generateRandomString() . '_' . time();
        $model->status = 1;

        if (!$model->save()) {
            if ($cycle_index <= 3) {
                $cycle_index++;
                return self::getAccessToken($member, $cycle_index);
            }

            throw new UnprocessableEntityHttpException($this->getError($model));
        }

        // 2.记录用户登录次数
        Yii::$app->services->member->lastLogin($member);
        $member = ArrayHelper::toArray($member);

        // 写入缓存
        $this->cache === true && Yii::$app->redis->setex($this->getCacheKey($model->access_token), $this->timeout, serialize($model));

        // 查询用户属性
        $memberAttr = Yii::$app->services->attr->findList([
            'member_id' => $member['id'],
        ]);
        $defaultProject = 0;// 默认项目ID
        if ($memberAttr) {
            $defaultProject = $memberAttr[0]['project_id'];
        }

        $memberInfo = Yii::$app->services->member->findById($member['id']);

        return [
            'access_token' => $model->access_token,
            'info' => [
                'member_id' => $member['id'],
                'username' => $member['realname'],
                'realname' => $member['realname'],
                'email' => $member['email'],
                'mobile' => $member['mobile'],
                'is_super' => $member['is_super'],
                'project_id' => $defaultProject,
                'head_img_url' => $memberInfo->head_img ? ImageHelper::getImagePathUrl($memberInfo->head_img) : '',
                'is_bind_dingtalk' => $member['ding_unionid'] ? 1 : 0,
            ],
        ];
    }

    /**
     * @param $token
     * @param $type
     * @return array|mixed|null|ActiveRecord
     */
    public function getTokenToCache($token, $type)
    {
        //Yii::warning('TRACE_1: DB_CONNECTION =' . env('DB_CONNECTION'). ':host=' . env('DB_HOST') . ';dbname=' . env('DB_DATABASE'));
        if ($this->cache == false) {
            //Yii::warning('TRACE_2:DEBUG:cache=false; TOKEN =' . $token);
            return $this->getTokenByAccessToken($token);
        }

        $key = $this->getCacheKey($token);
        //Yii::warning('TRACE_3:DEBUG:cache=true; TOKEN =' . $token . '; $key = ' . json_encode($key) . ';  unserialize result: ' . json_encode(unserialize(Yii::$app->redis->get($key))));
        if (!($model = unserialize(Yii::$app->redis->get($key)))) {
            //Yii::warning('TRACE_4:DEBUG:cache=true; TOKEN =' . $token);
            $model = $this->getTokenByAccessToken($token);
            if ($model) {
                //Yii::warning('TRACE_5:DEBUG:cache=true; $model =' . json_encode($model));
                Yii::$app->redis->setex($key, $this->timeout, serialize($model));
            }
        }

        return $model;
    }

    /**
     * 获取token
     *
     * @param $token
     * @return array|null|ActiveRecord|AccessToken
     */
    public function getTokenByAccessToken($token)
    {
        return AccessToken::find()
            ->where(['access_token' => $token, 'status' => 1])
            ->one();
    }

    /**
     * 禁用token
     *
     * @param $access_token
     * @return bool
     */
    public function disableByAccessToken($access_token)
    {
        $this->cache === true && Yii::$app->redis->del($this->getCacheKey($access_token));

        if ($model = $this->getTokenByAccessToken($access_token)) {
            $model->status = AccessToken::STATUS_DELETED;
            return $model->save();
        }
    }

    /**
     * @param $access_token
     * @return string
     */
    protected function getCacheKey($access_token)
    {
        return Yii::$app->params['redis.access_token'] . $access_token;
    }

    /**
     * 返回模型
     *
     * @param $member_id
     * @return array|AccessToken|null|ActiveRecord
     */
    protected function findModel($member_id)
    {
        if (empty(($model = AccessToken::find()->where([
            'member_id' => $member_id,
        ])->one()))) {
            $model = new AccessToken();
            return $model->loadDefaultValues();
        }

        return $model;
    }

    /**
     * 清空token
     * @param int $id
     * @return void
     */
    public static function clearMemberToken(int $id)
    {
        AccessToken::updateAll(['status' => AccessToken::STATUS_DELETED], ['member_id' => $id]);
    }
}
